package gps;

import gps_api.Problem;
import gps_api.Rule;
import gps_api.State;

import java.util.List;


/**
 * Solve a generic problem with a given
 * method.
 * @author Pablo
 *
 */
public class ProductionSystem {
	private Problem problem;
	private SolverMethod solverMethod;

	public ProductionSystem(Problem problem, SolverMethod solverMethod){
		this.problem= problem;
		this.solverMethod= solverMethod;
	}

	public void runSystem(){
		boolean goal= false;
		State state;
		List<Rule> rules;
		Node fatherNode=null;
		long startTime, stopTime;

		startTime= System.currentTimeMillis();

		rules= problem.getRules();
		solverMethod.initMethod(problem.getInitState());

		while(!solverMethod.isEmptyOpenNodes()){
			fatherNode= solverMethod.getNextNode();
			if(goal=problem.isGoal(fatherNode.getState())){
				break;
			}

			for (Rule rule : rules) {
				try
				{
					if(rule.isApplicable(fatherNode.getState())){
						state=rule.apply(fatherNode.getState());
						if(!solverMethod.hasEqualAncestor(state)){
							solverMethod.addChild(state, rule);
						}
					}
				}catch (Exception e) {
					System.out.println(e.toString());
				}
			}
		}


		if(goal){
			/* Found the solution */
			stopTime= System.currentTimeMillis();

			solverMethod.printSolution();
			System.out.println("Open List size: "+ solverMethod.getOpenListSize());
			System.out.println("Close List size: "+ solverMethod.getCloseListSize());
			System.out.println("Max level: "+ solverMethod.getMaxLevel());
			System.out.println("Solution level: "+ fatherNode.getLevel());
			System.out.println("Solution spend time: " + Long.toString(stopTime-startTime)+ " miliseconds");
		}else{
			System.out.println("Couldn't find solution");
		}


	}


	public Problem getProblem() {
		return problem;
	}

	public void setProblem(Problem problem) {
		this.problem = problem;
	}

	public SolverMethod getSolverMethod() {
		return solverMethod;
	}

	public void setSolverMethod(SolverMethod solverMethod) {
		this.solverMethod = solverMethod;
	}

}
